﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using UFIDA.U9.Base.FlexField.DescFlexField;
using UFIDA.U9.Base.FlexField.ValueSet;
using UFSoft.UBF.AopFrame.Lock;
using UFSoft.UBF.Cust.ClassView.MVC.Proxy;
using UFSoft.UBF.Cust.ClassView.MVC.Utils;
using UFSoft.UBF.MD;
using UFSoft.UBF.MD.DAO;
using UFSoft.UBF.MD.EntityModel;
using UFSoft.UBF.MD.ServiceModel;
using UFSoft.UBF.Sys.Database;
using UFSoft.UBF.Util.DataAccess;
using UFSoft.UBF.Util.DB;

namespace UFSoft.UBF.Cust.ClassView.MVC.Metedata
{
    /// <summary>
    ///     元数据帮助类
    /// </summary>
    public static class MetedataHelper
    {
        /// <summary>
        ///     默认属性分组名称
        /// </summary>
        private const string DefaultAttributeGroupName = "Misc";

        #region Entity

        /// <summary>
        ///     获取实体
        /// </summary>
        /// <param name="entityFullName"></param>
        /// <returns></returns>
        public static IEntity GetEntity(string entityFullName)
        {
            IEntityMetaDataService entityMetaDataService =
                (IEntityMetaDataService) MDSFactory.GetService(typeof(IEntityMetaDataService));
            IType type = entityMetaDataService.GetType(entityFullName);
            return type as IEntity;
        }

        /// <summary>
        ///     获取实体元数据
        /// </summary>
        /// <param name="entityFullName"></param>
        /// <returns></returns>
        public static EntityDTO GetEntityMetedata(string entityFullName)
        {
            IEntity entity = GetEntity(entityFullName);
            return entity == null ? null : CreateEntityDTO(entity);
        }

        /// <summary>
        ///     创建实体DTO
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static EntityDTO CreateEntityDTO(IEntity entity)
        {
            if (entity == null) return null;
            EntityDTO entityDTO = new EntityDTO();
            SetEntityDTO(entityDTO, entity);
            return entityDTO;
        }

        /// <summary>
        ///     设置实体DTO
        /// </summary>
        /// <param name="entityDTO"></param>
        /// <param name="entity"></param>
        public static void SetEntityDTO(EntityDTO entityDTO, IEntity entity)
        {
            SetTypeDTO(entityDTO, entity);
            entityDTO.IsGlobalization = entity.IsGlobalization;
            entityDTO.IsAuthority = entity.IsAuthority;
            entityDTO.IsMain = entity.IsMain;
            entityDTO.DefaultTableName = entity.DefaultTableName;
            entityDTO.ForOBAImport = entity.ForOBAImport;
            entityDTO.InheritanceMapKind = entity.InheritanceMapKind;
            entityDTO.Discriminator = entity.Discriminator;
            entityDTO.MainEntityKey = entity.MainEntity == null ? null : CreateKeyDTO(entity.MainEntity);
            entityDTO.IsAbstract = entity.IsAbstract;
            entityDTO.IsSealed = entity.IsSealed;
            entityDTO.TargetDimensionName = entity.TargetDimensionName;
            entityDTO.TargetCubeName = entity.TargetCubeName;
            entityDTO.IsFactEntity = entity.IsFactEntity;
            entityDTO.IsDimensionEntity = entity.IsDimensionEntity;
            entityDTO.BKAttributes = entity.BKAttributes;
            entityDTO.IsModifyControl = entity.IsModifyControl;
            entityDTO.HasImpressibleAttribute = entity.HasImpressibleAttribute;
            entityDTO.IsInCache = entity.IsInCache;
        }

        #endregion

        #region Enum

        /// <summary>
        ///     获取枚举元数据
        /// </summary>
        /// <param name="enumTypeName"></param>
        /// <returns></returns>
        public static EnumDTO GetEnumMetedata(string enumTypeName)
        {
            IEntityMetaDataService entityMetaDataService =
                (IEntityMetaDataService) MDSFactory.GetService(typeof(IEntityMetaDataService));
            IEnumType enumType = entityMetaDataService.GetEnumType(enumTypeName);
            return enumType == null ? null : CreateEnumDTO(enumType);
        }

        /// <summary>
        ///     创建枚举DTO
        /// </summary>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static EnumDTO CreateEnumDTO(IEnumType enumType)
        {
            if (enumType == null) return null;
            EnumDTO enumDTO = new EnumDTO();
            SetEnumDTO(enumDTO, enumType);
            return enumDTO;
        }

        /// <summary>
        ///     设置枚举DTO
        /// </summary>
        /// <param name="enumDTO"></param>
        /// <param name="enumType"></param>
        public static void SetEnumDTO(EnumDTO enumDTO, IEnumType enumType)
        {
            SetTypeDTO(enumDTO, enumType);
            enumDTO.IsExtend = enumType.IsExtend;
            string enumTypeID = enumType.ID.ToString();
            //补全程序集名、组件名称
            if (!string.IsNullOrEmpty(enumTypeID))
            {
                //设置类型的程序集
                SetTypeAssemblyName(enumDTO, enumTypeID);
            }
        }

        #endregion

        #region BPSV

        /// <summary>
        ///     获取BPSV元数据
        /// </summary>
        /// <param name="bpsv"></param>
        /// <returns></returns>
        public static ServiceDTO GetBPSVMetedata(string bpsv)
        {
            IServiceModelService serviceModelService =
                (IServiceModelService) MDSFactory.GetService(typeof(IServiceModelService));
            IService service = serviceModelService.GetService(bpsv);
            if (service == null)
            {
                ClassDAO classDAO = new ClassDAO();
                Row row = new Row();
                row.AddColumn("ID", "105423E7-5F1B-4B56-A966-5403D071FFBF");
                service = classDAO.GetTypeByCondition(row) as IService;
            }

            return service == null ? null : CreateServiceDTO(service);
        }

        /// <summary>
        ///     创建服务DTO
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public static ServiceDTO CreateServiceDTO(IService service)
        {
            if (service == null) return null;
            ServiceDTO serviceDTO = new ServiceDTO();
            SetServiceDTO(serviceDTO, service);
            return serviceDTO;
        }

        /// <summary>
        ///     设置服务DTO
        /// </summary>
        /// <param name="serviceDTO"></param>
        /// <param name="service"></param>
        public static void SetServiceDTO(ServiceDTO serviceDTO, IService service)
        {
            SetTypeDTO(serviceDTO, service);
            serviceDTO.TransactionType = service.TransactionType;
            serviceDTO.IsInterface = service.IsInterface;
            serviceDTO.IsDefault = service.IsDefault;
            serviceDTO.IsService = service.IsService;
            try
            {
                serviceDTO.ReturnType = CreateTypeDTO(service.ReturnType);
            }
            catch (Exception e)
            {
            }

            serviceDTO.IsReturnCollection = service.IsReturnCollection;
            string serviceID = service.ID.ToString();
            if (!string.IsNullOrEmpty(serviceID))
            {
                //设置类型的程序集
                SetTypeAssemblyName(serviceDTO, serviceID);
            }

            //加载代理类
            Type agentType;
            if (ProxyHelper.TryLoadProxy(serviceDTO.FullName, serviceDTO.AssemblyName, out agentType))
            {
                serviceDTO.ProxyName = agentType.Name;
                serviceDTO.ProxyFullName = agentType.FullName;
                serviceDTO.ProxyAssemblyName = agentType.Assembly.FullName.Split(',')[0];
            }
        }

        #endregion

        #region PropertyType

        /// <summary>
        ///     获取属性元数据
        /// </summary>
        /// <param name="propertyTypeName"></param>
        /// <param name="parentFullName"></param>
        public static PropertyTypeDTO GetPropertyTypeMetedata(string propertyTypeName, string parentFullName)
        {
            IEntityMetaDataService serviceModelService =
                (IEntityMetaDataService) MDSFactory.GetService(typeof(IEntityMetaDataService));
            IPropertyType propertyType = serviceModelService.GetPropertyType(propertyTypeName);
            PropertyTypeDTO typeDTO = propertyType == null ? null : CreatePropertyTypeDTO(propertyType);
            if (typeDTO == null || string.IsNullOrEmpty(parentFullName) ||
                propertyTypeName != Constant.DescFlexSegmentsFullName)
                return typeDTO;
            Dictionary<string, AttributeDTO> attributeDTOs = new Dictionary<string, AttributeDTO>();
            foreach (AttributeDTO attribute in typeDTO.Attributes)
            {
                attributeDTOs.Add(attribute.Name, attribute);
            }

            typeDTO.Attributes = new List<AttributeDTO>();
            using (new BPForEngine())
            {
                DescFlexFieldDef descFlexFieldDef = DescFlexFieldDef.FindByName(parentFullName);
                if (descFlexFieldDef == null) return typeDTO;
                foreach (DescFlexContext context in descFlexFieldDef.DescFlexContexts)
                {
                    if (context.ContextValue == "Public")
                    {
                        for (int i = 1; i <= context.DescFlexSegments.Count; i++)
                        {
                            DescFlexSegment seg = context.DescFlexSegments[i - 1];
                            AttributeDTO attributeDTO = attributeDTOs["PubDescSeg" + seg.Number];
                            attributeDTO.DescFlexFieldDef = CreateDescFlexFieldDefDTO(seg);
                            typeDTO.Attributes.Add(attributeDTO);
                        }
                    }

                    if (context.ContextValue == "Global")
                    {
                        for (int i = 1; i <= context.DescFlexSegments.Count; i++)
                        {
                            DescFlexSegment seg = context.DescFlexSegments[i - 1];
                            AttributeDTO attributeDTO = attributeDTOs["PrivateDescSeg" + seg.Number];
                            attributeDTO.DescFlexFieldDef = CreateDescFlexFieldDefDTO(seg);
                            typeDTO.Attributes.Add(attributeDTO);
                        }
                    }
                }
            }

            return typeDTO;
        }

        /// <summary>
        ///     创建扩展字段定义
        /// </summary>
        /// <param name="seg"></param>
        /// <returns></returns>
        public static DescFlexFieldDefDTO CreateDescFlexFieldDefDTO(DescFlexSegment seg)
        {
            DescFlexFieldDefDTO defDTO = new DescFlexFieldDefDTO();
            defDTO.Number = seg.Number;
            defDTO.Name = seg.Name;
            defDTO.ValueSetDef = CreateValueSetDefDTO(seg.ValueSetDef);
            return defDTO;
        }

        /// <summary>
        ///     创建值集定义DTO
        /// </summary>
        /// <param name="def"></param>
        /// <returns></returns>
        public static ValueSetDefDTO CreateValueSetDefDTO(ValueSetDef def)
        {
            ValueSetDefDTO defDTO = new ValueSetDefDTO();
            defDTO.ID = def.ID;
            defDTO.Code = def.Code;
            defDTO.Name = def.Name;
            defDTO.ValidateType = def.ValidateType.Value;
            defDTO.ValueType = def.ValueType.Value;
            defDTO.Pricision = def.Pricision;
            defDTO.MinValue = def.MinValue;
            defDTO.MaxValue = def.MaxValue;
            defDTO.Length = def.Length;
            defDTO.EnumType = def.EnumType == null
                ? null
                : KeyDTO.Create(def.EnumType.UID.ToString(), def.EnumType.Name, def.EnumType.Code, def.EnumType.Name);
            defDTO.EntityType = def.EntityType == null
                ? null
                : KeyDTO.Create(def.EntityType.UID.ToString(), def.EntityType.Name, def.EntityType.FullName,
                    def.EntityType.DisplayName);
            defDTO.IDAttribute = def.IDAttribute == null
                ? null
                : KeyDTO.Create(def.IDAttribute.DataTypeUID.ToString(), def.IDAttribute.Name, string.Empty,
                    def.IDAttribute.DisplayName);
            defDTO.CodeAttribute = def.CodeAttribute == null
                ? null
                : KeyDTO.Create(def.CodeAttribute.DataTypeUID.ToString(), def.CodeAttribute.Name, string.Empty,
                    def.CodeAttribute.DisplayName);
            defDTO.NameAttribute = def.NameAttribute == null
                ? null
                : KeyDTO.Create(def.NameAttribute.DataTypeUID.ToString(), def.NameAttribute.Name, string.Empty,
                    def.NameAttribute.DisplayName);
            defDTO.Condition = def.Condition;
            defDTO.ConditionDisplayName = def.ConditionDisplayName;
            return defDTO;
        }

        /// <summary>
        ///     创建属性DTO
        /// </summary>
        /// <param name="propertyType"></param>
        /// <returns></returns>
        public static PropertyTypeDTO CreatePropertyTypeDTO(IPropertyType propertyType)
        {
            if (propertyType == null) return null;
            PropertyTypeDTO propertyTypeDTO = new PropertyTypeDTO();
            SetPropertyTypeDTO(propertyTypeDTO, propertyType);
            return propertyTypeDTO;
        }

        /// <summary>
        ///     设置属性DTO
        /// </summary>
        /// <param name="propertyTypeDTO"></param>
        /// <param name="propertyType"></param>
        public static void SetPropertyTypeDTO(PropertyTypeDTO propertyTypeDTO, IPropertyType propertyType)
        {
            SetTypeDTO(propertyTypeDTO, propertyType);
            propertyTypeDTO.IsQueryDTO = propertyType.IsQueryDTO;
        }

        #endregion

        #region Type

        /// <summary>
        ///     创建类型DTO
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static TypeDTO CreateTypeDTO(IType type)
        {
            if (type == null) return null;
            TypeDTO typeDTO = new TypeDTO();
            SetTypeDTO(typeDTO, type);
            return typeDTO;
        }

        /// <summary>
        ///     设置类型DTO
        /// </summary>
        /// <param name="typeDTO"></param>
        /// <param name="type"></param>
        public static void SetTypeDTO(TypeDTO typeDTO, IType type)
        {
            SetElementDTO(typeDTO, type);
            typeDTO.ParentKey = CreateKeyDTO(type.Parent);
            typeDTO.FullName = type.FullName;
            typeDTO.AssemblyName = type.AssemblyName;
            typeDTO.ModuleKey = CreateKeyDTO(type.Module);
            //typeDTO.ComponentKey = CreateKeyDTO(type.C);
            typeDTO.ComponentName = type.ComponentName;
            typeDTO.IsPrimitiveType = type.IsPrimitiveType;
            typeDTO.IsEntity = type.IsEntity;
            typeDTO.IsEnumType = type.IsEnumType;
            typeDTO.IsPropertyType = type.IsPropertyType;
            typeDTO.IsCollectionType = type.IsCollectionType;
            typeDTO.IsOperator = type.IsOperator;
            typeDTO.IsValidator = type.IsValidator;
            typeDTO.IsEntityView = type.IsEntityView;
            typeDTO.Attributes = new List<AttributeDTO>();
            bool isEntity = type is IEntity;
            IAttributeCollection attributes = isEntity ? ((IEntity) type).GetAttributes() : type.Attributes;
            foreach (IAttribute attribute in attributes)
            {
                if (isEntity && Constant.EntitySysFieldNames.Contains(attribute.Name)) continue;
                typeDTO.Attributes.Add(CreateAttributeDTO(attribute));
            }

            typeDTO.Associations = new List<AssociationDTO>();
            if (type.Associations != null && type.Associations.Count > 0)
            {
                foreach (IAssociation association in type.Associations)
                {
                    typeDTO.Associations.Add(CreateAssociationDTO(association));
                }
            }

            typeDTO.ChildAssociations = new List<AssociationDTO>();
            //if (type.ChildAssociations != null && type.ChildAssociations.Count > 0)
            //{
            //    foreach (IAssociation childAssociation in type.ChildAssociations)
            //    {
            //        typeDTO.ChildAssociations.Add(CreateAssociationDTO(childAssociation));
            //    }
            //}
        }

        /// <summary>
        ///     创建节点DTO
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static ElementDTO CreateElementDTO(IElement element)
        {
            if (element == null) return null;
            ElementDTO elementDTO = new ElementDTO();
            SetElementDTO(elementDTO, element);
            return elementDTO;
        }

        /// <summary>
        ///     设置节点DTO
        /// </summary>
        /// <param name="elementDTO"></param>
        /// <param name="element"></param>
        public static void SetElementDTO(ElementDTO elementDTO, IElement element)
        {
            elementDTO.Key = CreateKeyDTO(element);
            elementDTO.Name = element.Name;
            elementDTO.DisplayName = string.IsNullOrEmpty(element.DisplayName) ? element.Name : element.DisplayName;
            //elementDTO.Description = element.Description;
            //版型
            if (element.Stereotypes != null)
            {
                elementDTO.Stereotypes = new List<StereotypeDTO>();
                foreach (IStereotype stereotype in element.Stereotypes)
                {
                    StereotypeDTO stereotypeDTO = new StereotypeDTO();
                    elementDTO.Stereotypes.Add(stereotypeDTO);
                    SetElementDTO(stereotypeDTO, stereotype);
                    stereotypeDTO.Template = stereotype.Template;
                    if (stereotype.TaggedValues != null)
                    {
                        stereotypeDTO.TaggedValues = new List<TaggedValueDTO>();
                        foreach (ITaggedValue taggedValue in stereotype.TaggedValues)
                        {
                            TaggedValueDTO taggedValueDTO = new TaggedValueDTO();
                            stereotypeDTO.TaggedValues.Add(taggedValueDTO);
                            SetElementDTO(taggedValueDTO, taggedValue);
                            taggedValueDTO.Value = taggedValue.Value;
                        }
                    }
                }
            }
        }

        /// <summary>
        ///     创建KeyDTO
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static KeyDTO CreateKeyDTO(IElement element)
        {
            if (element == null) return null;
            KeyDTO keyDTO = new KeyDTO();
            keyDTO.ID = element.ID.ToString();
            keyDTO.Name = element.Name;
            keyDTO.DisplayName = element.DisplayName;
            IType type = element as IType;
            if (type != null)
                keyDTO.FullName = type.FullName;
            return keyDTO;
        }

        /// <summary>
        ///     创建AttributeDTO
        /// </summary>
        /// <param name="attr"></param>
        /// <returns></returns>
        public static AttributeDTO CreateAttributeDTO(IAttribute attr)
        {
            AttributeDTO attributeDTO = new AttributeDTO();
            SetElementDTO(attributeDTO, attr);
            attributeDTO.DataTypeFlag = attr.DataTypeFlag;
            attributeDTO.DataTypeKey = CreateKeyDTO(attr.DataType);
            attributeDTO.Visibility = attr.Visibility;
            attributeDTO.IsNullable = attr.IsNullable;
            attributeDTO.ForOBAImport = attr.ForOBAImport;
            attributeDTO.IsReadOnly = attr.IsReadOnly;
            attributeDTO.DefaultValue = attr.DefaultValue;
            attributeDTO.MaxValue = attr.MaxValue;
            attributeDTO.MinValue = attr.MinValue;
            attributeDTO.Length = attr.Length;
            attributeDTO.Precision = attr.Precision;
            attributeDTO.Scale = attr.Scale;
            attributeDTO.Sequence = attr.Sequence;
            attributeDTO.IsKey = attr.IsKey;
            attributeDTO.IdGenerator = attr.IdGenerator;
            attributeDTO.IsGlobalized = attr.IsGlobalized;
            attributeDTO.IsCalculation = attr.IsCalculation;
            attributeDTO.IsAuthority = attr.IsAuthority;
            attributeDTO.ValueExpression = attr.ValueExpression;
            attributeDTO.IsCollection = attr.IsCollection;
            attributeDTO.IsSystem = attr.IsSystem;
            attributeDTO.IsBusinessKey = attr.IsBusinessKey;
            attributeDTO.GroupId = attr.GroupId;
            attributeDTO.IsModifyControl = attr.IsModifyControl;
            attributeDTO.IsDynamic = attr.IsDynamic;
            attributeDTO.IsImpressible = attr.IsImpressible;
            attributeDTO.IsInCache = attr.IsInCache;
            attributeDTO.IsKeySerializable = attr.IsKeySerializable;
            attributeDTO.DefaultColumnName = attr.DefaultColumnName;
            attributeDTO.IsQueryAttribute = attr.IsQueryAttribute;
            attributeDTO.IsForAsso = attr.IsForAsso;
            attributeDTO.IsDefaultDimensionAttribute = attr.IsDefaultDimensionAttribute;
            attributeDTO.IsDefaultMeasureAttribute = attr.IsDefaultMeasureAttribute;
            attributeDTO.IsColumnDefine = attr.IsColumnDefine;
            attributeDTO.IsFilterDefine = attr.IsFilterDefine;
            attributeDTO.IsSortDefine = attr.IsSortDefine;
            attributeDTO.IsDefaultColumn = attr.IsDefaultColumn;
            attributeDTO.IsHide = attr.IsHide;
            attributeDTO.IsShare = attr.IsShare;
            attributeDTO.GroupName = string.IsNullOrEmpty(attr.GroupName) ? DefaultAttributeGroupName : attr.GroupName;
            attributeDTO.IsEntityKey = attr.IsEntityKey;
            attributeDTO.IsEntityData = attr.IsEntityData;
            return attributeDTO;
        }

        /// <summary>
        ///     创建AssociationDTO
        /// </summary>
        /// <param name="asso"></param>
        /// <returns></returns>
        public static AssociationDTO CreateAssociationDTO(IAssociation asso)
        {
            AssociationDTO associationDTO = new AssociationDTO();
            SetElementDTO(associationDTO, asso);
            associationDTO.ParentEntityKey = CreateKeyDTO(asso.ParentEntity);
            associationDTO.ChildEntityKey = CreateKeyDTO(asso.ChildEntity);
            associationDTO.ParentMemberKey = CreateKeyDTO(asso.ParentMember);
            associationDTO.ChildMemberKey = CreateKeyDTO(asso.ChildMember);
            associationDTO.ParentCardinality = asso.ParentCardinality;
            associationDTO.ChildCardinality = asso.ChildCardinality;
            associationDTO.IsCascadeDelete = asso.IsCascadeDelete;
            associationDTO.CascadeDeleteRule = asso.CascadeDeleteRule;
            associationDTO.IsCascadeUpdate = asso.IsCascadeUpdate;
            associationDTO.IsEnableCascadeValidation = asso.IsEnableCascadeValidation;
            associationDTO.CascadeUpdateRule = asso.CascadeUpdateRule;
            associationDTO.Kind = asso.Kind;
            associationDTO.Direction = asso.Direction;
            associationDTO.ParentMemberName = asso.ParentMemberName;
            associationDTO.ChildMemberName = asso.ChildMemberName;
            if (asso.ChildEntity != null && !string.IsNullOrEmpty(asso.ChildEntity.FullName))
            {
                IEntity childEntity = GetEntity(asso.ChildEntity.FullName);
                if (childEntity != null)
                {
                    //子实体是否有子实体
                    associationDTO.ChildEntityHasChildren =
                        childEntity?.Associations != null && childEntity.Associations.Cast<IAssociation>()
                            .Any(association => association.Kind == EnumAssociationKind.COMPOSITION);
                    associationDTO.ChildEntityTableName = childEntity.DefaultTableName;
                }
            }

            return associationDTO;
        }

        /// <summary>
        ///     设置类型的程序集
        /// </summary>
        /// <param name="typeDTO"></param>
        /// <param name="classTypeID"></param>
        public static void SetTypeAssemblyName(TypeDTO typeDTO, string classTypeID)
        {
            string strSql = string.Format(@"
SELECT B.AssemblyName AS AssemblyName,
       B.Name AS ComponentName
FROM UBF_MD_Class AS A
    INNER JOIN UBF_MD_Component AS B
        ON A.MD_Component_ID = B.ID
WHERE A.ID =  '{0}'", classTypeID);
            DataSet dataSet;
            DataAccessor.RunSQL(DatabaseManager.GetCurrentConnection(), strSql, null, out dataSet);
            if (dataSet == null || dataSet.Tables.Count <= 0 || dataSet.Tables[0].Rows.Count <= 0) return;
            DataRow row = dataSet.Tables[0].Rows[0];
            typeDTO.AssemblyName = DataRowConverter.AsString(row, "AssemblyName");
            typeDTO.ComponentName = DataRowConverter.AsString(row, "ComponentName");
        }

        #endregion
    }
}